%{
#include <stdio.h>
#include "util-define.h"
#include "sintatico-arvore.h"


int yylex(void); /* function prototype */

void yyerror(char *s)
{
 std::cout << s << "\n";
}

no *root;

%}


%union {
  dadoToken *token;
  no *nttoken;
}

%token <token> 	t_identifier t_integer t_string
		t_comma t_colon t_semicolon 
	       	t_lparen t_rparen t_lbrack t_rbrack t_lbrace t_rbrace 
	       	t_dot t_plus t_minus t_time t_divide 
	       	t_eq t_neq t_lt t_le t_gt t_ge t_and t_or t_assign 
		t_array t_if t_then t_else t_while t_for t_to t_do t_let t_in t_end t_of
		t_break t_nil t_function t_var t_type t_new t_class t_extends t_method t_import t_primitive

%type <nttoken> NT_INICIO NT_PROGRAM NT_EXP NT_DECS NT_OP NT_TYPE_ID NT_CONT_EXP NT_LVALUE NT_PARAMS NT_CONT_PARAMS NT_EXPS NT_CONT_EXPS NT_CONT_COLON NT_TY NT_TYFIELDS
		NT_CONT_TYFIELDS NT_ELSE NT_DEC NT_CONT_LVALUE


%start NT_INICIO

//%left 	    t_semicolon t_colon t_comma
//%nonassoc   t_function t_var t_type t_then t_do t_of t_assign                                 
//%left       t_or                                        
//%left       t_and
//%nonassoc   t_identifier                                     
%nonassoc   t_eq t_neq t_lt t_le t_gt t_ge  
%left 	    t_minus t_plus
%left       t_time t_divide
//%left       t_lparen t_lbrack
//%left       t_rbrack                                                        


%%

NT_INICIO:  NT_PROGRAM {root = $1; };
 
NT_PROGRAM: NT_EXP { std::cout << "NT_PROGRAM: NT_EXP\n"; $$ = new no(NTPROGRAM); $$->addChild($1); }
	  | NT_DECS { std::cout << "NT_PROGRAM: NT_DECS\n"; $$ = new no(NTPROGRAM); $$->addChild($1); };
	     
NT_EXP: 
   //literais
     t_nil { std::cout << "NT_EXP t_nil\n"; $$ = new no($1,"nil"); }
   | t_integer { std::cout << "NT_EXP t_integer\n"; $$ = new no($1,"integer");}
   | t_string {std::cout << "NT_EXP t_string\n"; $$ = new no($1,"string");}
   
   //Array e criacao de registros  
//   | NT_TYPE_ID t_of NT_EXP {}    
//   | NT_TYPE_ID NT_EXP t_of NT_EXP {}      
   | NT_TYPE_ID t_lbrack NT_EXP t_rbrack t_of NT_EXP { std::cout << "NT_EXP NT_TYPE_ID t_lbrack \n"; $$ = new no(NTARRAYEXP); $$->addChild($1); $$->addChild($3); $$->addChild($6);}

   | NT_TYPE_ID t_lbrace t_identifier t_eq NT_EXP t_rbrace { std::cout << "NT_EXP NT_TYPE_ID t_lbrace t_identifier \n"; $$ = new no(NTREGEXP); $$->addChild($1); $$->addChild(new no($3)); $$->addChild($5); }
   | NT_TYPE_ID t_lbrace NT_CONT_EXP t_rbrace { std::cout << "NT_EXP NT_TYPE_ID t_lbrace NT_CONT_EXP  \n"; $$ = new no(NTREGEXP); $$->addChild($1); $$->addChild($3);}

   //Instancia
   | t_new NT_TYPE_ID { std::cout << "NT_EXP t_new\n"; $$ = new no(NTINSTANCIAEXP); $$->addChild($2); }
   
   //Variaveis, campos e elementos do array
   | NT_LVALUE { std::cout << "NT_EXP NT_LVALUE\n"; $$ = new no(NTVAREXP); $$->addChild($1); }
   
   //Chamada de funcao
   | t_identifier t_lparen t_rparen { std::cout << "NT_EXP t_identifier t_lparen t_rparen\n";$$ = new no(NTCALLFUNCEXP); $$->addChild(new no($1)); }
   | t_identifier t_lparen NT_PARAMS t_rparen { std::cout << "NT_EXP t_identifier t_lparen NT_PARAMS\n"; $$ = new no(NTCALLFUNCEXP); $$->addChild(new no($1)); $$->addChild($3); }
   
   //Chamada de metodo  
   | NT_LVALUE t_dot t_identifier t_lparen t_rparen { std::cout << "NT_EXP NT_LVALUE t_dot t_identifier t_lparen t_rparen\n"; $$ = new no(NTCALLMETHEXP); $$->addChild($1); $$->addChild(new no($3)); }
   | NT_LVALUE t_dot t_identifier t_lparen NT_PARAMS t_rparen {std::cout << "NT_EXP NT_LVALUE t_dot t_identifier t_lparen NT_PARAMS t_rparen\n"; $$ = new no(NTCALLMETHEXP); $$->addChild($1); $$->addChild(new no($3)); $$->addChild($5);}
   
   //Operacoes
   | t_minus NT_EXP { std::cout << "NT_EXP t_minus\n"; $$ = new no(NTOPMINUSEXP); $$->addChild(new no($1)); $$->addChild($2);}
   | NT_EXP NT_OP NT_EXP { std::cout << "NT_EXP NT_EXP\n"; $$ = new no(NTOPEXP); $$->addChild($1); $$->addChild($2);  $$->addChild($3);}   
   | t_lparen t_rparen { std::cout << "NT_EXP t_lparen t_rparen\n"; $$ = new no(NTOPPAREMEXP);}
   | t_lparen NT_EXPS t_rparen { std::cout << "NT_EXP t_lparen NT_EXPS\n"; $$ = new no(NTOPPAREMEXP); $$->addChild($2); }
   
   //Atribuicao
   | NT_LVALUE t_assign NT_EXP { std::cout << "NT_EXP NT_LVALUE t_assign\n"; $$ = new no(NTASSIGNEXP); $$->addChild($1); $$->addChild($3);}
   
   //Controle de estruturas
   | t_if NT_EXP t_then NT_EXP NT_ELSE {std::cout << "NT_EXP t_if\n"; $$ = new no(NTIFEXP); $$->addChild($2); $$->addChild($4); $$->addChild($5);}
   | t_while NT_EXP t_do NT_EXP { std::cout << "NT_EXP t_while\n"; $$ = new no(NTWHILEEXP); $$->addChild($2); $$->addChild($4);}
   | t_for t_identifier t_assign NT_EXP t_to NT_EXP t_do NT_EXP { std::cout << "NT_EXP t_for\n"; $$ = new no(NTFOREXP); $$->addChild(new no($2)); $$->addChild($4); $$->addChild($6); $$->addChild($8);}
   | t_break { std::cout << "NT_EXP t_break\n";  $$ = new no(NTBREAKEXP);}
   | t_let NT_DECS t_in t_end { std::cout << "NT_EXP t_let NT_DECS t_in t_end \n";  $$ = new no(NTLETEXP); $$->addChild($2); }
   | t_let NT_DECS t_in NT_EXPS t_end { std::cout << "NT_EXP t_let NT_DECS t_in NT_EXPS t_end \n"; $$ = new no(NTLETEXP); $$->addChild($2); $$->addChild($4); }
   ;
   
   
//continuacao de expressoes de array e criacao de registros       
NT_CONT_EXP: t_identifier t_eq NT_EXP { std::cout << "NT_CONT_EXP: t_identifier t_eq NT_EXP\n";  $$ = new no(NTCONTEXP); $$->addChild(new no($1)); $$->addChild($3);}
	   | t_identifier t_eq NT_EXP t_comma NT_CONT_EXP { std::cout << "NT_CONT_EXP: t_identifier t_eq NT_EXP t_comma\n";  $$ = new no(NTEXP); $$->addChild(new no($1)); $$->addChild($3); $$->addChild($5);}
	   ;

//parametro funcao e metodo	   
NT_PARAMS: NT_EXP NT_CONT_PARAMS {std::cout << "NT_PARAMS\n"; $$ = new no(NTPARAMS); $$->addChild($1); $$->addChild($2); };
	 
//continuacao de parametros da funcao e metodo
NT_CONT_PARAMS: t_comma NT_PARAMS { std::cout << "NT_CONT_PARAMS t_comma\n"; $$ = new no(NTCONTPARAMS); $$->addChild($2);}
	      |  {std::cout << "NT_CONT_EXP: vazio\n"; $$ = new no(NTCONTPARAMS);} ;
	      
NT_LVALUE: t_identifier NT_CONT_LVALUE {std::cout << "NT_LVALUE t_identifier\n"; $$ = new no(NTLVALUE); $$->addChild(new no($1)); $$->addChild($2); };
        
NT_CONT_LVALUE: t_dot t_identifier { std::cout << "NT_CONT_LVALUE t_dot\n"; $$ = new no(NTMENBROCONTLVALUE); $$->addChild(new no($2));}
        | t_lbrack NT_EXP t_rbrack { std::cout << "NT_CONT_LVALUE t_lbrack\n"; $$ = new no(NTINDICECONTLVALUE); $$->addChild($2);}
        |  {std::cout << "NT_CONT_LVALUE vazio\n"; $$ = new no(NTCONTLVALUE); };
       
//expressoes de operacoes
NT_EXPS: NT_EXP NT_CONT_EXPS { std::cout << "NT_EXPS: NT_EXP NT_CONT_EXPS \n"; $$ = new no(NTEXPS); $$->addChild($1); $$->addChild($2);};

//continuacao de expressoes de operacoes
NT_CONT_EXPS: t_semicolon NT_EXPS {std::cout << "NT_CONT_EXPS: t_semicolon\n"; $$ = new no(NTCONTEXPS); $$->addChild($2); }
	      |  {std::cout << "NT_CONT_EXPS: vazio\n"; $$ = new no(NTCONTEXPS); };
	      
//if then ou if then else
NT_ELSE: t_else NT_EXP { std::cout << "NT_ELSE t_else\n"; $$ = new no(NTELSE); $$->addChild($2); }
       |  {std::cout << "NT_ELSE: vazio\n"; $$ = new no(NTELSE); };

//declaracao       
NT_DECS: NT_DEC NT_DECS { std::cout << "NT_DECS: NT_DEC\n"; $$ = new no(NTDECS); $$->addChild($1);  $$->addChild($2);}
       |  {std::cout << "NT_DECS: vazio\n"; $$ = new no(NTDECS);};

//tipo de declaracoes 
NT_DEC: t_type t_identifier t_eq NT_TY { std::cout << "NT_DEC t_type\n"; $$ = new no(NTTYPEDEC); $$->addChild(new no($2)); $$->addChild($4); }  
      | t_var t_identifier NT_CONT_COLON t_assign NT_EXP { std::cout << "NT_DEC t_var\n"; $$ = new no(NTVARDEC); $$->addChild(new no($2)); $$->addChild($3);  $$->addChild($5); } 
      | t_function t_identifier t_lparen NT_TYFIELDS t_rparen NT_CONT_COLON t_eq NT_EXP { std::cout << "NT_DEC t_function\n"; $$ = new no(NTFUNCDEC); $$->addChild(new no($2)); $$->addChild($4); $$->addChild($6); $$->addChild($8);};

      
//continuacao de declaracoes de variaveis, campo da classe, funcoes
NT_CONT_COLON: t_colon t_identifier {std::cout << "NT_CONT_COLON t_colon\n"; $$ = new no(NTCONTCOLON); $$->addChild(new no($2));}
	     |  {std::cout << "NT_CONT_COLON vazio\n"; $$ = new no(NTCONTCOLON);} ;
       
//tipos 
NT_TY: NT_TYPE_ID { std::cout << "NT_TY NT_TYPE_ID\n"; $$ = new no(NTIDENTTY); $$->addChild($1); }
     | t_lbrace NT_TYFIELDS t_rbrace { std::cout << "NT_TY t_lbrace\n"; $$ = new no(NTINDICETY); $$->addChild($2);}
     | t_array t_of NT_TYPE_ID { std::cout << "NT_TY: t_array\n"; $$ = new no(NTARRAYTY); $$->addChild($3); };
        
//tipos de campo
NT_TYFIELDS: t_identifier t_colon NT_TYPE_ID  NT_CONT_TYFIELDS { std::cout << "NT_TYFIELDS t_identifier\n"; $$ = new no(NTTYFIELDS); $$->addChild(new no($1)); $$->addChild($3);  $$->addChild($4); }
	   |  {std::cout << "NT_TYFIELDS vazio\n"; $$ = new no(NTTYFIELDS);} ;
	   
//continuacao de tipos de campo
NT_CONT_TYFIELDS: t_comma t_identifier t_colon NT_TYPE_ID NT_CONT_TYFIELDS { std::cout << "NT_CONT_TYFIELDS t_comma\n"; $$ = new no(NTCONTFIELDS); $$->addChild(new no($2)); $$->addChild($4);  $$->addChild($5);}
		|  {std::cout << "NT_CONT_TYFIELDS vazio\n"; $$ = new no(NTCONTFIELDS);};

		         
//tipo de indenticador		
NT_TYPE_ID: t_identifier { std::cout << "NT_TYPE_ID t_identifier\n"; $$ = new no(NTTYPEID); $$->addChild(new no($1));};

//operacoes
NT_OP: t_plus { std::cout << "NT_OP +\n"; $$ = new no($1);}
     | t_minus {std::cout << "NT_OP -\n"; $$ = new no($1);}
     | t_time {std::cout << "NT_OP x\n"; $$ = new no($1);}
     | t_divide {std::cout << "NT_OP / \n"; $$ = new no($1);}
     | t_eq { std::cout << "NT_OP =\n"; $$ = new no($1);}
     | t_neq {std::cout << "NT_OP !\n"; $$ = new no($1);}
     | t_gt {std::cout << "NT_OP >\n"; $$ = new no($1);}
     | t_lt {std::cout << "NT_OP <\n"; $$ = new no($1);}
     | t_ge {std::cout << "NT_OP >=\n"; $$ = new no($1);}
     | t_le {std::cout << "NT_OP <=\n"; $$ = new no($1);}
     | t_and {std::cout << "NT_OP and\n"; $$ = new no($1);}
     | t_or {std::cout << "NT_OP or\n"; $$ = new no($1);}
     ;


/*NT_OPERACAO: NT_MULTI {} 
	   | NT_EXP t_plus NT_EXP {}
	   | NT_EXP t_minus NT_EXP {} ;

NT_MULTI: NT_LOG {}
	| NT_EXP t_time NT_EXP {}
	| NT_EXP t_divide NT_EXP {};
	
NT_LOG: NT_EXP t_eq NT_EXP{}
      | NT_EXP t_neq NT_EXP{}
      | NT_EXP t_gt NT_EXP{}
      | NT_EXP t_lt NT_EXP{}
      | NT_EXP t_ge NT_EXP{}
      | NT_EXP t_le NT_EXP{}
      | NT_EXP t_and NT_EXP{}
      | NT_EXP t_or NT_EXP{};	*/
	
	

/*soma: mul
    | soma '+' soma
    | soma '-' soma

mul: log
   | mul * mul
   | mul / mul

log: */

%%      

